home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Sample Code / Printing Samples / Printer Drivers… / LaserWriterIISC / LaserSCIntf.c < prev    next >
Encoding:
Text File  |  1993-09-13  |  31.9 KB  |  996 lines  |  [TEXT/MPS ]

  1. /*----------------------------------------------------------------------------------------------
  2. FILENAME
  3.  
  4.     LaserSCIntf.c
  5.     
  6. DESCRIPTION
  7.  
  8.     This file contains routines for invoking commands within the command set provided by the 
  9.     LaserWriter SC and IISC. Routines within this file utilize the WriteData and CheckStatus
  10.     printing messages to in order to communicate with the printer. The actual SCSI code used to
  11.     perform the I/O to the printer is implemented in the SD_WriteData, SD_CheckStatus and
  12.     SD_GetDeviceStatus routines within the UniversalMessageIntf.c file.  The routines in this 
  13.     file provide a "higher level" interface to the SC/IISC by hiding the details of the SC/IISC 
  14.     commands and their implementation. 
  15.  
  16.     9/13/93 - dmh - Updated for the b2 seed.
  17.  
  18. COPYRIGHT
  19.  
  20.     Copyright Apple Computer, Inc.  1989-1992
  21.     All rights reserved.
  22.     
  23. ROUTINES IN THIS MODULE:
  24.  
  25.     interface routines:
  26.         LaserSC_OpenConn()
  27.         LaserSC_GetDeviceStatus()
  28.         LaserSC_ResetDevice()
  29.         LaserSC_GetSenseData()
  30.         LaserSC_SetPageMargins()
  31.         LaserSC_SetPageDimensions()
  32.         LaserSC_ClearBits()
  33.         LaserSC_DrawBits()
  34.         LaserSC_PrintPage()
  35.         LaserSC_QueryPrinter()
  36.         LaserSC_SetBuffandFeedMode()
  37.         LaserSC_GetTimeoutForSCSICmnd()
  38.  
  39.     
  40. -----------------------------------------------------------------------------------------------*/
  41.  
  42. // Include the standard Mac header files 
  43. #include "MacIncludes.h"
  44.  
  45. // Include the new QuickDraw GX graphics header files 
  46. #include <graphics routines.h>
  47. #include <graphics libraries.h>
  48. #include <math routines.h>
  49.  
  50. // Include the required Printing Manager header files 
  51. #include <PrintingManager.h>
  52. #include <PrintingMessages.h>
  53. #include <PrintingDrivers.h>
  54. #include <Collections.h>
  55. #include <Messages.h>
  56. #include <PrintingResTypes.h>
  57. #include <PrintingErrors.h>
  58.  
  59. #include <Exceptions.h>
  60.  
  61. // Include the internal driver constants and types used by this module 
  62. #include "Resources.h"
  63. #include "UniversalMessageIntf.h"
  64. #include "LaserSCIntf.h"
  65.  
  66.  
  67. /*********************************************************************************
  68.  *                                         CONSTANTS                                                     *
  69.  *********************************************************************************/
  70.  
  71. // Miscellaneous constants
  72. enum
  73. {
  74.     minSCSICmndSz            = 5,            // Min. # of inquiry bytes returned by all SCSI devices
  75.  
  76.     kMaxRowBytes            = 304,            // max rowBytes supported by SC printer
  77.  
  78.     kPrintFromSCRam            = 0x0080,        //    Bit in the SCSI Print page command that sets the "print from printer RAM" attribute
  79.     kPrintContinuous        = 0x0040,        //    Bit in the SCSI Print page command that sets the "print a 8 ppm rate" attribute
  80.     kClearWhilePrinting        = 0x0020,        //    Bit in the SCSI Print page command that sets the "clear page while page is being printed" attribute
  81.  
  82.     kBuffered                = 2,            // These constants are used to set the manual feed and buffered mode of the printer
  83.     kFeed                        = 4,
  84.     kManual                    = 0x01,
  85.     kBufferedMode            = 0x10
  86. };
  87.  
  88.  
  89. /*********************************************************************************
  90.  *                                         TYPES                                                         *
  91.  *********************************************************************************/
  92.  
  93. // SCSICommData - structure that defines the layout of the SCSI version of the 'comm' resource
  94.  
  95. typedef struct
  96. {
  97.     ResType                    commType;                // communications type ('sPTL')
  98.     
  99.     ProcPtr                    releaseDevice;            // Pointer to C routine that can release SCSI device,
  100.                                                     // can be nil (N/A for this driver)
  101.     short                    scsiIOAttributes;        // SCSI I/O attributes applicable to data xfers (N/A for this driver)
  102.     short                    *statusByte;            // Location to store status byte from data xfer operation,
  103.                                                     // can be nil (N/A for this driver)
  104.     short                    scsiBus;                // Number of scsi bus to which device is attached (0 = motherboard; applies to open connection call only). (N/A for this driver)
  105.     short                    deviceNum;                // Number of scsi device to open connection to (applies to open connection call only). (N/A for this driver)
  106.     long                    bytesPerChunk;            // 0 => ignored; > 0 => break data transfer into chunks
  107.                                                     // of this size (at SCSI TIB level). (N/A for this driver)
  108.     ProcPtr                    acquireDevice;            // Pointer to C routine that can acquire SCSI device,
  109.                                                     // nil == use info below in standard routine (N/A for this driver)
  110.     short                    deviceKind;                // device kind to look for in reponse
  111.     short                    minLength;                // minimum additional data to get in response
  112.     short                    offsetStart;            // offset from start of returned data to look at (N/A for this driver)
  113.     Str255                    searchString;            // string to search for in the response
  114. }    SCSICommData,
  115.     *SCSICommDataPtr,
  116.     **SCSICommDataHdl;
  117.  
  118.  
  119. /*********************************************************************************
  120.  *                                         DEFINES                                                         *
  121.  *********************************************************************************/
  122.  
  123. // Useful defines for doing I/O to the printer
  124.  
  125. #define    SendSCSICmnd(pCmnd, cmndSize)                            Send_GXWriteData(pCmnd, cmndSize)
  126. #define    GetDataFromPrinter(inputBuff, numToGet, scsiChunkSize)    Send_GXGetDeviceStatus(nil, scsiChunkSize, inputBuff, numToGet, "\p")
  127. #define    SendDataToPrinter(outputBuff, numToSend, scsiChunkSize)    Send_GXCheckStatus(outputBuff, numToSend, scsiChunkSize, kDrvrCreatorType)
  128. #define    GetLastSCSIStatus(lastStatus)                            Send_GXGetDeviceStatus(nil, 0, nil, lastStatus, "\p")
  129.  
  130.  
  131. /***************************************************************************************
  132. *                                         INTERNAL ROUTINES                                                     *
  133. ***************************************************************************************/                        
  134.  
  135. /********************************************************************************************
  136.  
  137.                                         EqlByteStream
  138.     function:
  139.                 EqlByteStream compares two byte streams, for a specified number of characters, to 
  140.                 determine if they are equal. 
  141.     
  142.     parameters:
  143.                 stream1                    Pointer to first byte stream
  144.                 stream2                    Pointer to second byte stream
  145.                 bytesToChk                Number of bytes to compare in the two streams
  146.     
  147.     returns:
  148.                 EqlByteStream            Returns true if byte strings equal; false otherwise
  149.                     
  150. ********************************************************************************************/
  151. Boolean EqlByteStream(Ptr stream1, Ptr stream2, short bytesToChk)
  152. {
  153.     Boolean    theyMatch = true;
  154.     
  155.     // Assume streams will match initially
  156.     
  157.     for (; bytesToChk > 0; --bytesToChk)
  158.     {
  159.         if (*stream1++ != *stream2++)    // T => Streams don't match
  160.         {
  161.             theyMatch = false;
  162.             break;
  163.         }
  164.     }
  165.     
  166.     return(theyMatch);
  167. }
  168. /* EqlByteStream */
  169.  
  170.  
  171. /********************************************************************************************
  172.  
  173.                                         DeviceIsSCPrinter
  174.     function:
  175.                 DeviceIsSCPrinter queries the specified SCSI device to determine if it's a
  176.                 SC/IISC printer. If is, it returns true; otherwise it returns false.  The
  177.                 device to query is specified by the 
  178.     
  179.     parameters:
  180.                 scsiCommData    Handle to the 'comm' resource in the target DTP file
  181.     
  182.     returns:
  183.                 Boolean            Returns true if selected device is a SC/IISC printer; false otherwise
  184.                     
  185. ********************************************************************************************/
  186. Boolean DeviceIsSCPrinter(SCSICommDataHdl scsiCommData)
  187. {
  188.     OSErr                anErr;
  189.     SCInquiryData        queryData;
  190.     Boolean                isOurPrinter = false;
  191.     short                amntInqData;
  192.     
  193.     // Query the device to determine if it's a printer
  194.     
  195.     anErr = LaserSC_QueryPrinter(&queryData, minSCSICmndSz);
  196.     require(anErr == noErr, QueryPrinterFails1);
  197.     
  198.     // Device responded. Now see how much more data we can read from the device
  199.     
  200.     amntInqData = queryData.additionalLength + minSCSICmndSz;
  201.     if (amntInqData > sizeof(SCInquiryData)) // T => Only read max. bytes query record can hold
  202.         amntInqData = sizeof(SCInquiryData);
  203.         
  204.     // Now read as much of the query data as we can from the device
  205.     
  206.     anErr = LaserSC_QueryPrinter(&queryData, amntInqData);
  207.     require(anErr == noErr, QueryPrinterFails2);
  208.  
  209.     // Finally we can determine if the device is an SC/IISC
  210.     {
  211.         SCSICommDataPtr    pCommData = *scsiCommData;
  212.         
  213.         if (queryData.peripheralType == pCommData->deviceKind)    // T => Responding device is a printer
  214.         {
  215.             if (queryData.additionalLength >= pCommData->minLength)    // T => Device gave us enough additional query data
  216.             {
  217.                 // Do the device product names match? 
  218.                 isOurPrinter = EqlByteStream(    ((Ptr) &queryData) + pCommData->offsetStart, 
  219.                                                         &pCommData->searchString[1], 
  220.                                                         pCommData->searchString[0]);
  221.             }
  222.         }
  223.     }
  224.     
  225.     
  226. /******* Clean-up *******/
  227.  
  228. QueryPrinterFails2:
  229. QueryPrinterFails1:
  230.     return(isOurPrinter);
  231. }
  232. /* DeviceIsSCPrinter */
  233.  
  234.  
  235. /***************************************************************************************
  236. *                                         INTERFACE ROUTINES                                                     *
  237. ***************************************************************************************/                        
  238.  
  239. /********************************************************************************************
  240.  
  241.                                         LaserSC_OpenConnection
  242.     function:
  243.                 This routine establishes a connection to the LaserWriter SC/IISC referenced 
  244.                 in the current Job.  To determine which SCSI device number to use, we 
  245.                 extract the 'comm' resource from the target Desktop Printer file and use
  246.                 the deviceNum field in the SCSICommData handle that is returned.
  247.                 
  248.                 If LaserSC_OpenConnection is successful, the client should always call 
  249.                 LaserSC_SetPageMargins and LaserSC_SetPageDimensions to ensure the printer's 
  250.                 page buffer is properly initialized. Failure to call these routines could 
  251.                 reduce the life of the printing engine.
  252.  
  253.     parameters:
  254.                 None
  255.                     
  256.     returns:
  257.                 OSErr
  258.                     
  259. ********************************************************************************************/
  260. OSErr LaserSC_OpenConnection()
  261. {
  262.     OSErr                    anErr;
  263.     SpecGlobalsHdl             hGlobals = GetMessageHandlerInstanceContext();
  264.     Str31                    printerName;
  265.     SCSICommDataHdl            scsiCommData;
  266.  
  267.     // Get the name of the target desktop printer
  268.     
  269.     GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), printerName);
  270.     
  271.     // Now extract the SCSI 'comm' resource to get at the device number
  272.     
  273.     anErr = GXFetchDTPData(printerName, gxDeviceCommunicationsType, gxDeviceCommunicationsID, (Handle *) &scsiCommData);
  274.     require(anErr == noErr, GXFetchDTPData);
  275.     
  276.     // Set the deviceNum field in the globals to be the device we want to access
  277.     (*hGlobals)->deviceNum = (*scsiCommData)->deviceNum;
  278.     
  279.     // Is the target device a LaserWriter SC/IISC printer?
  280.     if ( !DeviceIsSCPrinter(scsiCommData) )
  281.         anErr = gxAioCantFindDevice;
  282.  
  283.     // Dump the resource handle we fetched
  284.     DisposeHandle((Handle) scsiCommData);
  285.     
  286.     check(anErr == noErr);
  287.  
  288.     
  289. /******* Clean-up *******/
  290.  
  291. GXFetchDTPData:
  292.     return(anErr);
  293. }
  294. /* LaserSC_OpenConnection */
  295.  
  296.  
  297. /********************************************************************************************
  298.  
  299.                                         LaserSC_GetDeviceStatus
  300.     function:
  301.                 LaserSC_GetDeviceStatus queries the printer to determine if it's ready to print.
  302.                 It returns a deviceStatus parameter which indicates the current readiness state of
  303.                 the device (kGoodCondition, kCheckCondition, or kBusy). If the device is in a
  304.                 check condition state, the client can call LaserSC_GetSenseData to determine the 
  305.                 exact reason why the device isn't ready.
  306.  
  307.     parameters:
  308.                 deviceStatus        Returns the current status of the device
  309.     
  310.     returns:
  311.                 OSErr
  312.                     
  313. ********************************************************************************************/
  314. OSErr LaserSC_GetDeviceStatus(short *deviceStatus)
  315. {
  316.     OSErr            anErr;
  317.     short            scsiCommand[3];
  318.     long            cmndSz;
  319.     long            lastStatus;
  320.     
  321.     // Set up the test for ready SCSI command to be sent to the printer
  322.     
  323.     scsiCommand[0] = kSCPrinterReady;
  324.     scsiCommand[1] = kSCReserved;
  325.     scsiCommand[2] = kSCReserved;
  326.     cmndSz             = 6;
  327.     
  328.     // Send the SCSI command to the device
  329.     
  330.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  331.     require(anErr == noErr, SendSCSICmndFails);
  332.     
  333.     // Now fetch the last status of the device
  334.     
  335.     anErr = GetLastSCSIStatus(&lastStatus);
  336.     require(anErr == noErr, GetLastSCSIStatusFails);
  337.     
  338.     // Return the last status
  339.     *deviceStatus = lastStatus;
  340.         
  341.  
  342. /******* Clean-up *******/
  343.  
  344. GetLastSCSIStatusFails:
  345. SendSCSICmndFails:
  346.     return(anErr);
  347. }
  348. /* LaserSC_GetDeviceStatus */
  349.  
  350.  
  351. /********************************************************************************************
  352.  
  353.                                         LaserSC_ResetDevice
  354.     function:
  355.                 LaserSC_ResetDevice will reset the LaserWriter SC/IISC to its default power-up
  356.                 state (without performing the power-up diagnostics).
  357.                     
  358.     parameters:
  359.                 none    
  360.                 
  361.     returns:
  362.                 OSErr
  363.                     
  364. ********************************************************************************************/
  365. OSErr LaserSC_ResetDevice()
  366. {
  367.     OSErr        anErr;
  368.     short        scsiCommand[3];
  369.     long        cmndSz;
  370.     
  371.     // Set up the reset SCSI command to be sent to the printer
  372.     
  373.     scsiCommand[0] = kSCResetPrinter;
  374.     scsiCommand[1] = kSCReserved;
  375.     scsiCommand[2] = kSCReserved;
  376.     cmndSz             = 6;
  377.     
  378.     // Send the SCSI command to the device
  379.     
  380.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  381.     require(anErr == noErr, SendSCSICmndFails);
  382.  
  383.  
  384. /******* Clean-up *******/
  385.  
  386. SendSCSICmndFails:
  387.     return(anErr);
  388. }
  389. /* LaserSC_ResetDevice */
  390.  
  391.  
  392. /********************************************************************************************
  393.  
  394.                                         LaserSC_GetSenseData
  395.     function:
  396.                 LaserSC_GetSenseData returns the sense data for the printer which reflects the
  397.                 last "Check Condition" status. This call is useful to determine the current 
  398.                 state of the hardware and the result of the last executed command. A structure
  399.                 of type SCSenseData is returned which contains all state information
  400.                 available from the printer.
  401.                         
  402.     parameters:
  403.                 senseData            Pointer to a SCSenseData record in which to store the 
  404.                                         the current status information.
  405.     
  406.     returns:
  407.                 OSErr
  408.                     
  409. ********************************************************************************************/
  410. OSErr LaserSC_GetSenseData(SCSenseDataPtr senseData)
  411. {
  412.     OSErr        anErr;
  413.     short        scsiCommand[3];
  414.     long        cmndSz;
  415.     long        responseSz;
  416.     
  417.     // Validate the pointer parameter
  418.     check(senseData != nil);
  419.     
  420.     // Set up the request sense SCSI command to be sent to the printer
  421.     
  422.     scsiCommand[0] = kSCRequestSense;
  423.     scsiCommand[1] = kSCReserved;
  424.     scsiCommand[2] = sizeof(SCSenseData) << 8;        // High byte contains number of bytes to read
  425.     cmndSz             = 6;
  426.     
  427.     // Send the SCSI command to the device
  428.     
  429.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  430.     require(anErr == noErr, SendSCSICmndFails);
  431.  
  432.     // Now read the request sense data from the device
  433.     
  434.     responseSz = sizeof(SCSenseData);
  435.  
  436.     anErr = GetDataFromPrinter((Ptr) senseData, &responseSz, responseSz);
  437.     require(anErr == noErr, GetDataFromPrinterFails);
  438.     
  439.     
  440. /******* Cleanup *******/
  441.  
  442. GetDataFromPrinterFails:
  443. SendSCSICmndFails:
  444.     return(anErr);
  445. }
  446. /* LaserSC_GetSenseData */
  447.  
  448.  
  449. /********************************************************************************************
  450.  
  451.                                         LaserSC_SetPageMargins
  452.     function:
  453.                 LaserSC_SetPageMargins sets the page margins associated with the page buffer
  454.                 maintained by the printer. These margins should always be set when the printer
  455.                 is powered on in order to ensure that imaging doesn't occur off the paper.
  456.                 Imaging outside of the paper can reduce the life of the laser printing engine.
  457.                 These margins define the top and left margins of the imageable area of the page.
  458.                 
  459.                 This routine accepts two parameters, which represent the top margin and the
  460.                 left margin of the page. The top margin specifies the number of lines from 
  461.                 the top of the page, where each line is 1/300 of an inch. The top margin 
  462.                 should never be set to less that 0x76 or .197 inches. The left margin
  463.                 specifies the width of the left margin in bytes (byte = 8/300th inch). 
  464.                 Incrementing or decrementing this field by one adjusts the left margin by 
  465.                 8/300th inch. The left margin should not be set to less that .197 inches.
  466.                 
  467.                 To calculate the left margins for a new paper size, keep in mind the paper is
  468.                 fed into the printer center justified. This means if the width of the paper 
  469.                 decreases by .5 inches, the Left Margin would be increased by only .25 inches.
  470.                     
  471.     parameters:
  472.                 leftMargin            Left margin of the printer's page 
  473.                 topMargin            Top margin of the printer's page 
  474.     
  475.     returns:
  476.                 OSErr
  477.                     
  478. ********************************************************************************************/
  479. OSErr LaserSC_SetPageMargins(short leftMargin, short topMargin)
  480. {
  481.     OSErr            anErr;
  482.     short            scsiCommand[3];
  483.     long            cmndSz;
  484.     long            dataSz;
  485.     short            params[2];
  486.     
  487.     // Validate the parameters to ensure they aren't too small
  488.     check((topMargin >= kMinSCTopMargin) && (leftMargin >= kMinSCLeftMargin));
  489.     
  490.     // Set up the format SCSI command to be sent to the printer
  491.     
  492.     scsiCommand[0] = kSCFormatMargin;
  493.     scsiCommand[1] = kSCReserved;
  494.     scsiCommand[2] = 0x0400;                // High byte contains the length of the parameters being sent (4 = 2 * sizeof(short))
  495.     cmndSz             = 6;
  496.     
  497.     // Send the SCSI command to the device
  498.     
  499.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  500.     require(anErr == noErr, SendSCSICmndFails);
  501.  
  502.     // Send the parameters to the set margins command on to the device
  503.     
  504.     params[0]     = topMargin;        
  505.     params[1]     = leftMargin;
  506.     dataSz         = 4;
  507.     anErr = SendDataToPrinter((Ptr) params, dataSz, dataSz);
  508.     require(anErr == noErr, SendDataToPrinterFails);
  509.     
  510.     
  511. /******* Cleanup *******/
  512.  
  513. SendDataToPrinterFails:
  514. SendSCSICmndFails:
  515.     return(anErr);
  516. }
  517. /* LaserSC_SetPageMargins */
  518.  
  519.  
  520. /********************************************************************************************
  521.  
  522.                                         LaserSC_SetPageDimensions
  523.     function:
  524.                 LaserSC_SetPageDimensions sets the page dimensions associated with the page buffer
  525.                 maintained by the printer. These dimensions should always be set when the printer
  526.                 is powered on in order to ensure that imaging doesn't occur off the paper.
  527.                 Imaging outside of the paper can reduce the life of the laser printing engine.
  528.                 These dimensions define the number of lines per page and the number of bytes
  529.                 per line. 
  530.                 
  531.                 LaserSC_SetPageDimensions accepts two parameters, the number of bytes per line
  532.                 and the number of scan lines per page. The byes per line parameter specifies
  533.                 the width of the image in bytes, where each byte represents 8/300th of an
  534.                 inch (8 pixels). This parameter must be an even number and cannot be greater
  535.                 that 304. The number of scan lines per page parameter specifies the length
  536.                 of the image in lines, where each line represents 1/300th of an inch
  537.                 (1 pixel height).
  538.                 
  539.                 These two parameters define the dimensions of an image whose top left
  540.                 corner is assumed to start at coordinate (0, 0). Positive coordinates increase
  541.                 downward and to the right. All drawing will take place within the rectangle:
  542.                 (0, 0, (Bytes per line) * 8, Number of Lines).
  543.                 
  544.     parameters:
  545.                 bytesPerScanLine    Number of bytes within each line of the page 
  546.                 numScanLines        Number of lines within the page 
  547.     
  548.     returns:
  549.                 OSErr
  550.                     
  551. ********************************************************************************************/
  552. OSErr LaserSC_SetPageDimensions(short bytesPerScanLine, short numScanLines)
  553. {
  554.     OSErr        anErr;
  555.     short        scsiCommand[3];
  556.     long        cmndSz;
  557.     long        dataSz;
  558.     short        params[2];
  559.     
  560.     // Make sure the parameters are within tolerance
  561.     check(((bytesPerScanLine % 2) == 0) && (bytesPerScanLine <= kMaxRowBytes));
  562.     
  563.     // Set up the format SCSI command to be sent to the printer
  564.     
  565.     scsiCommand[0] = kSCFormatImage;
  566.     scsiCommand[1] = kSCReserved;
  567.     scsiCommand[2] = 0x0400;                // High byte contains the length of the parameters being sent (4 = 2 * sizeof(short))
  568.     cmndSz = 6;
  569.     
  570.     // Send the SCSI command to the device
  571.     
  572.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  573.     require(anErr == noErr, SendSCSICmndFails);
  574.     
  575.     // Send the parameters to the set dimensions command on to the device
  576.     
  577.     params[0]     = bytesPerScanLine;        
  578.     params[1]     = numScanLines;
  579.     dataSz         = 4;
  580.     anErr = SendDataToPrinter((Ptr) params, dataSz, dataSz);
  581.     require(anErr == noErr, SendDataToPrinterFails);
  582.  
  583.  
  584. /******* Cleanup *******/
  585.  
  586. SendDataToPrinterFails:
  587. SendSCSICmndFails:
  588.     return(anErr);
  589. }
  590. /* LaserSC_SetPageDimensions */
  591.  
  592.  
  593. /********************************************************************************************
  594.  
  595.                                         LaserSC_ClearBits
  596.     function:
  597.                 LaserSC_ClearBits will clear all bits inside the printers page buffer defined
  598.                 by the specified rectangle. This command only applies to printers with one 
  599.                 megabyte of RAM installed. If this command is issued with bufferred mode in 
  600.                 effect (see routine below), the clear command will return immediately, before
  601.                 clearing begins. While the area is being cleared, the printer will not be 
  602.                 able to accept SCSI comands and will return a Device Busy status when
  603.                 queried.
  604.                     
  605.     parameters:
  606.                 rectToClear            Rectangle within the page buffer to clear
  607.     
  608.     returns:
  609.                 OSErr
  610.                     
  611. ********************************************************************************************/
  612. OSErr LaserSC_ClearBits(Rect *rectToClear)
  613. {
  614.     OSErr        anErr;
  615.     short        scsiCommand[3];
  616.     long        cmndSz;
  617.     long        dataSz;
  618.     short        params[4];
  619.     
  620.     // Set up the clear bits SCSI command to be sent to the printer
  621.     
  622.     scsiCommand[0] = kSCClearBits;
  623.     scsiCommand[1] = kSCReserved;
  624.     scsiCommand[2] = 0x0800;                // High byte contains the length of the parameters being sent (8 = 4 * sizeof(short))
  625.     cmndSz             = 6;
  626.     
  627.     // Send the SCSI command to the device
  628.     
  629.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  630.     require(anErr == noErr, SendSCSICmndFails);
  631.     
  632.     // Send the parameters to the clear bits command on to the device
  633.     
  634.     params[0]     =     rectToClear->left;
  635.     params[1]     =     rectToClear->top;
  636.     params[2]     =     rectToClear->right;
  637.     params[3]     =     rectToClear->bottom;
  638.     dataSz         =     8;
  639.     anErr = SendDataToPrinter((Ptr) params, dataSz, dataSz);
  640.     require(anErr == noErr, SendDataToPrinterFails);
  641.  
  642.     // Now we must wait until the device is no longer busy
  643.     {
  644.         short        deviceStatus;        
  645.     
  646.         do
  647.         {
  648.             // Get the latest status info from the printer
  649.             
  650.             anErr = LaserSC_GetDeviceStatus(&deviceStatus);
  651.             require(anErr == noErr, LaserSC_GetDeviceStatusFails);
  652.             
  653.             // Let the client app have a chance to run
  654.             anErr = GXJobIdle();
  655.             require(anErr == noErr, JobIdleFails);
  656.         }
  657.         while (deviceStatus == kBusy);
  658.     }
  659.     
  660.  
  661. /******* Cleanup *******/
  662.  
  663. JobIdleFails:
  664. LaserSC_GetDeviceStatusFails:
  665. SendDataToPrinterFails:
  666. SendSCSICmndFails:
  667.     return(anErr);
  668. }
  669. /* LaserSC_ClearBits */
  670.  
  671.  
  672. /********************************************************************************************
  673.  
  674.                                         LaserSC_DrawBits
  675.     function:
  676.                     LaserSC_DrawBits transfers image data into the specified rectangular area of
  677.                     the printer's page buffer using one of several QuickDraw transfer modes. This
  678.                     command only applies to printers with one megabyte of RAM installed.
  679.                     
  680.                     The routine accepts three parameters which specify the image data to transfer,
  681.                     the rectangle within the printer's page buffer in which to image the data, 
  682.                     and one of the QuickDraw transfer modes: srcCopy, srcOR, srcXOR, or srcBIC.
  683.     
  684.     parameters:
  685.                     imageData            Pointer to the data to image
  686.                     rectToDrawIn        Pointer to rectangle in which to image the data
  687.                     qdTransferMode        One of the QuickDraw transfer modes srcCopy, srcOR, srcXOR,
  688.                                             or srcBIC
  689.     
  690.     returns:
  691.                     noErr                    Success
  692.                     badIISCParam        imageData pointer is nil
  693.                     badTransferMode    invalid transfer modes passed to 
  694.                     
  695.                     Any other error codes that can be returned by the Async I/O software                        
  696.  
  697.     called from:
  698.                     LaserIISC Interface Call
  699.                     
  700. ********************************************************************************************/
  701. OSErr LaserSC_DrawBits(Ptr imageData, Rect *rectToDrawIn, short numBytesPerLine, short qdTransferMode)
  702. {
  703.     OSErr                anErr;
  704.     short                scsiCommand[3];
  705.     long                cmndSz;
  706.     long                dataSz;
  707.     short                params[5];
  708.     long                numImageLines;
  709.     
  710.     // Initially validate the parameters 
  711.     
  712.     check((imageData != nil) && (rectToDrawIn != nil));
  713.     check((qdTransferMode == srcCopy)     ||
  714.             (qdTransferMode == srcOr)         ||
  715.             (qdTransferMode == srcXor)     ||
  716.             (qdTransferMode == srcBic));
  717.     
  718.     // Set up the draw bits SCSI command to be sent to the printer
  719.     
  720.     scsiCommand[0] = kSCDrawBits;
  721.     scsiCommand[1] = kSCReserved;
  722.     scsiCommand[2] = 0x0A00;                // High byte contains the length of the parameters being sent (10 = 4 * sizeof(short) + sizeof(short))
  723.     cmndSz             = 6;
  724.     
  725.     // Send the SCSI command to the device
  726.     
  727.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  728.     require(anErr == noErr, SendSCSICmndFails);
  729.     
  730.     // Now set up to send the rectangle to draw in and the transfer mode, and send it
  731.     
  732.     params[0]     =     rectToDrawIn->left;
  733.     params[1]     =     rectToDrawIn->top;
  734.     params[2]     =     rectToDrawIn->right;
  735.     params[3]     =     rectToDrawIn->bottom;
  736.     params[4]     =     qdTransferMode;
  737.     dataSz         =     10;
  738.     anErr = SendDataToPrinter((Ptr) params, dataSz, dataSz);
  739.     require(anErr == noErr, SendDataToPrinterFails1);
  740.     
  741.     // Now set up to pass the bit image to the draw bits command
  742.     
  743.     numImageLines = rectToDrawIn->bottom - rectToDrawIn->top;
  744.     dataSz = numImageLines * numBytesPerLine;
  745.  
  746.     // Now send the bitmap. We negate the last parameter to indicate the SCSI transfer should be a blind transfer.
  747.     // Also, the SCSI transfer chunk size is set to the number of bytes in 1 scan line
  748.     
  749.     anErr = SendDataToPrinter(imageData, dataSz, -(numBytesPerLine));
  750.     require(anErr == noErr, SendDataToPrinterFails2);
  751.  
  752.  
  753. /******* Cleanup *******/
  754.  
  755. SendDataToPrinterFails2:
  756. SendDataToPrinterFails1:
  757. SendSCSICmndFails:
  758.     return(anErr);
  759. }
  760. /* LaserSC_DrawBits */
  761.  
  762.  
  763. /********************************************************************************************
  764.  
  765.                                         LaserSC_PrintPage
  766.     function:
  767.                 LaserSC_PrintPage prints the current contents of the printer's page buffer.
  768.                 As soon as the SCSI print command returns control to this routine, it
  769.                 returns to the caller.  If the printer is set for buffered mode, then when
  770.                 this routine returns the printer may still be busy printing the page.  Thus,
  771.                 if you're using the printer in buffered mode, you must make sure that the
  772.                 printer is no longer busy before you start sending data for the next page.
  773.                 
  774.                 The continuousPrint parameter can be used to attain the 8 page per minute
  775.                 rating of the IISC engine. Set this parameter to true to attain the improved
  776.                 rating. It should only be set true if the next print command will be issued
  777.                 in less than 7.4 seconds (8.7 for Legal paper). 
  778.                 
  779.                 Setting clearPage to true causes the image area in the printers memory to be
  780.                 cleared as the page is being printed. This substantially reduces the amount
  781.                 of time a client may wait for the printers page buffer to clear.
  782.     
  783.     parameters:
  784.                 continuousPrint    T => print at 8 page per minute rate; F => print normal rate
  785.                 clearPage            T => clear printers page buffer while printing; F => don't clear buffer
  786.     
  787.     returns:
  788.                 OSErr
  789.                     
  790. ********************************************************************************************/
  791. OSErr LaserSC_PrintPage(Boolean    continuousPrint, Boolean clearPage) 
  792. {
  793.     OSErr            anErr;
  794.     short            scsiCommand[3];
  795.     long            cmndSz;
  796.  
  797.     // Set up the print command to be sent to the printer
  798.     
  799.     scsiCommand[0] = kSCPrint;
  800.     scsiCommand[1] = kSCReserved;
  801.     scsiCommand[2] = kSCReserved;
  802.     
  803.     if (continuousPrint)    // T => Modify command to indicate 8 page per minute printing
  804.         scsiCommand[2] += kPrintContinuous;
  805.         
  806.     if (clearPage)    // T => Clear page while we print
  807.         scsiCommand[2] += kClearWhilePrinting;
  808.     
  809.     scsiCommand[2] += kPrintFromSCRam;    //    Always print from the printers RAM
  810.     cmndSz = 6;
  811.         
  812.     // Send the SCSI command to the device
  813.     
  814.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  815.     require(anErr == noErr, SendSCSICmndFails);
  816.     
  817.     
  818. /******* Cleanup *******/
  819.  
  820. SendSCSICmndFails:
  821.     return(anErr);
  822. }
  823. /* LaserSC_PrintPage */
  824.  
  825.  
  826. /********************************************************************************************
  827.  
  828.                                         LaserSC_QueryPrinter
  829.     function:
  830.                 LaserSC_QueryPrinter returns specific information about the printer (e.g. paper
  831.                 size, vendor, etc.). This call is useful to determine configuration information
  832.                 about the printer. A structure of type SCInquiryData is returned which 
  833.                 contains all configuration information available from the printer.
  834.                         
  835.     parameters:
  836.                 inquiryData            Pointer to a SCInquiryData record in which to store the 
  837.                                         the configuration information.
  838.                 querySize            amount of data (bytes) that should be read from device
  839.  
  840.     returns:
  841.                 OSErr
  842.                     
  843. ********************************************************************************************/
  844. OSErr LaserSC_QueryPrinter(SCInquiryDataPtr inquiryData, char querySize)
  845. {
  846.     OSErr            anErr;
  847.     short            scsiCommand[3];
  848.     long            cmndSz;
  849.     long            dataSz;
  850.     
  851.     // Set up the inquiry command to be sent to the printer as the write portion
  852.     // of a status command.
  853.     
  854.     scsiCommand[0] = kSCInquiry;
  855.     scsiCommand[1] = kSCReserved;
  856.     scsiCommand[2] = querySize << 8;        // Number of inquiry bytes to return
  857.     cmndSz = 6;
  858.  
  859.     // Send the SCSI command to the device
  860.     
  861.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  862.     require(anErr == noErr, SendSCSICmndFails);
  863.     
  864.     // Now read the query data from the device
  865.     
  866.     dataSz = querySize;
  867.     
  868.     anErr = GetDataFromPrinter((Ptr) inquiryData, &dataSz, dataSz);
  869.     require(anErr == noErr, GetDataFromPrinterFails);
  870.  
  871.  
  872. /******* Cleanup *******/
  873.  
  874. GetDataFromPrinterFails:
  875. SendSCSICmndFails:
  876.     return(anErr);
  877. }/* LaserSC_QueryPrinter */
  878.  
  879.  
  880. /********************************************************************************************
  881.  
  882.                                         LaserSC_SetBuffandFeedMode
  883.     function:
  884.                 LaserSC_SetBuffandFeedMode is used to change the manual feed and bufferred mode
  885.                 settings of the printer. Setting manualFeed to true informs the printer that 
  886.                 paper will be fed manually as opposed to automatically from the cassette.
  887.                 Setting bufferedMode to true causes the print from printer RAM and clear bits
  888.                 commands to return immediately, without waiting for the command to complete.
  889.                 If buffered mode is selected, the printer will return a device busy status 
  890.                 while the operation completes.
  891.     
  892.     parameters:
  893.                 manualFeed        T => pages will be manually fed into the printer; F => cassette fed
  894.                 bufferedMode    T => Don't wait for clear bits and print RAM commands to complete;
  895.                                     F => wait for them to complete.
  896.                                         
  897.     returns:
  898.                 OSErr
  899.                     
  900. ********************************************************************************************/
  901. OSErr LaserSC_SetBuffandFeedMode(Boolean manualFeed, Boolean bufferedMode)
  902. {
  903.     OSErr        anErr;
  904.     short        scsiCommand[3];
  905.     long        cmndSz;
  906.     long        dataSz;
  907.     char        params[12];
  908.     short        i;
  909.     
  910.     // Set up the mode select SCSI command to be sent to the printer
  911.     
  912.     scsiCommand[0] = kSCModeSelect;
  913.     scsiCommand[1] = kSCReserved;
  914.     scsiCommand[2] = 0x0C00;            // High bytes specifies # of bytes being sent to the printer
  915.     cmndSz = 6;
  916.     
  917.     // Send the SCSI command to the device
  918.     
  919.     anErr = SendSCSICmnd((Ptr) scsiCommand, cmndSz);
  920.     require(anErr == noErr, SendSCSICmndFails);
  921.     
  922.     // Now set up the mode select parameters to be passed to the printer
  923.     
  924.     for (i = 0; i <= 11; i++)    //    Zero all twelve bytes initially
  925.         params[i] = 0;
  926.     
  927.     if (manualFeed)    // T => Set for manual feed mode
  928.         params[kFeed] = kManual;
  929.         
  930.     if (bufferedMode)    // T => Set for buffered mode
  931.         params[kBuffered] = kBufferedMode;
  932.     
  933.     // Now send the parameters to the printer
  934.     
  935.     dataSz = 12;
  936.     anErr = SendDataToPrinter(params, dataSz, dataSz);
  937.     require(anErr == noErr, SendDataToPrinterFails);
  938.     
  939. /******* CLean-up *******/
  940.  
  941. SendDataToPrinterFails:
  942. SendSCSICmndFails:
  943.     return(anErr);
  944. }
  945. /* LaserSC_SetBuffandFeedMode */
  946.  
  947.  
  948. /********************************************************************************************
  949.  
  950.                                         LaserSC_GetTimeoutForSCSICmnd
  951.     function:
  952.                     This routine returns the timeout that should be used in the call to SCSIComplete
  953.                     when the specified printer command is forced to complete.
  954.     
  955.     parameters:
  956.                     scsiCmnd        SCSI command to be issued to the printer (generated by another
  957.                                     LaserSCIntf.c interface routine).
  958.                     
  959.     returns:
  960.                     long            timeout (in ticks) to use for the SCSIComplete call
  961.                     
  962. ********************************************************************************************/
  963. long LaserSC_GetTimeoutForSCSICmnd(short scsiCmnd)
  964. {
  965.     long    timeout;
  966.     
  967.     switch ( scsiCmnd )
  968.     {
  969.          case kSCPrinterReady:
  970.          case kSCResetPrinter:
  971.          case kSCRequestSense:
  972.          case kSCFormatMargin:
  973.          case kSCFormatImage:
  974.          case kSCInquiry:
  975.          case kSCDrawBits:
  976.          case kSCModeSelect:
  977.          case kSCReserveUnit:
  978.          case kSCReleaseUnit:
  979.          case kSCModeSense:
  980.             timeout = 240;
  981.             break;
  982.             
  983.          case kSCClearBits:
  984.             timeout = 480;
  985.             break;
  986.             
  987.          case kSCDownLoadCode:
  988.          case kSCPrint:
  989.             timeout = 4800;
  990.             break;
  991.     }
  992.     
  993.     return(timeout);
  994. }
  995. /* LaserSC_GetTimeoutForSCSICmnd */
  996.